Move 透過讀取和寫入 Tree 來實現持久的全局儲存,程式無法訪問此 Tree 之外的文件系統、網路或任意數據。
struct GlobalStorage {
resources: Map<(address, ResourceType), ResourceValue>
modules: Map<(address, ModuleName), ModuleBytecode>
}
全局儲存是由 address 和 Tree 互相搭配,如上面範例,每個地址都可以儲存資源數據值和模塊代碼值。
Move 可以使用下面五個指令在全局儲存中創建、刪除、和更新資源
move_to<T>(&signer,T)
move_from<T>(address): T
borrow_global_mut<T>(address): &mut T
borrow_global<T>(address): &T
exists<T>(address): bool
還記得上一篇提到的 type 四種能力的 key 能力,上述這些指令中都必須是具有 key 能力的類型。且每個類型 (T) 必須在當前 Module 中聲明,確保資源只能通做其定義 Module 的公開 API 進行操作。
本地引用和全局引用有個重要的區別,函數不能返回指向全局儲存的引用
:
struct R has key { f: u64 }
// will not compile
fun ret_direct_resource_ref_bad(a: address): &R {
borrow_global<R>(a) /// error
}
// also will not compile
fun ret_resource_field_ref_bad(a: address): &u64 {
&borrow_global<R>(a).f /// error
}
Move 必須強制執行此限制以保證不存在對全局儲存的懸空引用,我們後面也會介紹到。
全局存儲操作可以應用於具有實例化和未實例化的泛型類型參數的泛型資源:
通過在運行時選擇的類型參數對全局存儲進行索引的能力是一種強大的移動特性,稱為存儲多態性。我們在後面 Generic 章節會詳細介紹 T。
struct Container<T> has key { t: T }
// Publish a Container storing a type T of the caller's choosing
fun publish_generic_container<T>(account: &signer, t: T) {
move_to<Container<T>>(account, Container { t })
}
/// Publish a container storing a u64
fun publish_instantiated_generic_container(account: &signer, t: u64) {
move_to<Container<u64>>(account, Container { t })
}
下面的範例程式碼練習了五個全局儲存運算符中的每一個,該 Module 公開的 API 允許:
address 0x42 {
module Counter {
use Std::Signer;
/// Resource that wraps an integer counter
struct Counter has key { i: u64 }
/// Publish a `Counter` resource with value `i` under the given `account`
public fun publish(account: &signer, i: u64) {
move_to(account, Counter { i })
}
/// Read the value in the `Counter` resource stored at `addr`
public fun get_count(addr: address): u64 acquires Counter {
borrow_global<Counter>(addr).i
}
/// Increment the value of `addr`'s `Counter` resource
public fun increment(addr: address) acquires Counter {
let c_ref = &mut borrow_global_mut<Counter>(addr).i;
*c_ref = *c_ref + 1
}
/// Reset the value of `account`'s `Counter` to 0
public fun reset(account: &signer) acquires Counter {
let c_ref = &mut borrow_global_mut<Counter>(Signer::address_of(account)).i;
*c_ref = 0
}
/// Delete the `Counter` resource under `account` and return its value
public fun delete(account: &signer): u64 acquires Counter {
// remove the Counter resource
let c = move_from<Counter>(Signer::address_of(account));
let Counter { i } = c;
i
}
/// Return `true` if `addr` contains a `Counter` resource
public fun isExists(addr: address): bool {
exists<Counter>(addr)
}
}
}
Move 禁止返回全局引用,並且需要 acquires 註解來防止懸空引用。我們在上面的例子已經看過
public fun delete(account: &signer): u64 acquires Counter {
// remove the Counter resource
let c = move_from<Counter>(Signer::address_of(account));
let Counter { i } = c;
i
}
本篇介紹了前面幾篇一直提到的全局儲存,以及上篇的 key 能力。讓我們 Move to Day12
相關資料
Tree: https://en.wikipedia.org/wiki/Tree_(graph_theory)